package main

import (
	"github.com/gin-gonic/gin"
	"server/data"
	"server/model"
	"strconv"
)

func runUnsafeEngine(engine *gin.Engine) {
	err := engine.Run("0.0.0.0:80")
	if err != nil {
		print(err.Error())
	}
}

func hsts(ctx *gin.Context) {
	ctx.Header("Strict-Transport-Security", "max-age=31536000;includeSubDomains")
	ctx.Header("Content-Security-Policy", "default-src 'none'")
	ctx.Next()
}

func main() {
	// Redirect HTTP request to HTTPS.
	unsafeEngine := gin.New()
	unsafeEngine.GET("/*anyPath", func(context *gin.Context) {
		requestURL := context.Request.URL
		requestURL.Host = context.Request.Host
		requestURL.Scheme = "https"
		context.Redirect(301, requestURL.String())
	})
	go runUnsafeEngine(unsafeEngine)

	// HTTPS service provided by gin.
	engine := gin.New()

	// HSTS and CSP restrict.
	engine.Use(hsts)

	// Blank home page.
	engine.GET("/", func(context *gin.Context) {
		context.Status(204)
	})

	// Attachment service for some course.
	attachGroup := engine.Group("/attach")
	attachGroup.GET("/machine-learning", func(context *gin.Context) {
		context.File("attach/machine-learning.pdf")
	})

	// The AUGENBLICK project.
	courseGroup := engine.Group("/course")
	courseGroup.GET("/", func(context *gin.Context) {
		item, err := data.GetCourseItems(true)
		if err != nil {
			context.Status(400)
			println(err.Error())
			return
		}
		context.JSON(200, item)
	})
	engine.GET("/test", func(context *gin.Context) {
		obj, err := data.GetNarrationItems(false, "British English", "Mandarin", 1, 1, 1)
		if err != nil {
			context.Status(500)
			println(err.Error())
			return
		}
		context.JSON(200, *obj)
	})
	courseGroup.GET("/:target/:instruction/:tour/:lesson/:activity/:exercise", func(context *gin.Context) {
		activity := context.Param("activity")
		exercise := context.Param("exercise")
		switch activity {
		case "narration":
			context.JSON(200, gin.H{
				"random": true,
				"slides": []model.NarrationItem{{
					Spec: "1|Y|Q=v,A=ti",
					Slide: []model.SlideItem{{
						Spec:         "000001|N|Y|N|N",
						LanguageA:    "English",
						FontA:        "English",
						Text:         "The man is [r]under[-r] the car.",
						AlternativeA: "The man is on the car.",
						AlternativeB: "The girl is on the sofa.",
						LanguageB:    "English",
						FontB:        "English",
						MainSentence: "The man is [h]in[-h] the car.",
						Blanks:       [][]string{{"on", "under", "next to", "around", "with"}},
					}},
				}},
			})
			break
		case "lexis":
			switch exercise {
			case "1":
				// A Given B Cloze
				context.JSON(200, gin.H{
					"Type":    "A Given B Cloze",
					"Set":     1,
					"Comment": "Verbs change form in English",
					"items": []model.ClozeABItem{{
						SoundA:    "F2",
						LanguageA: "English",
						A:         "What is Jane doing",
						FontA:     "English",
						SoundB:    "M2",
						B:         "She [h]is eating[-h](eat) an apple.",
						LanguageB: "English",
						Answers:   []string{"is eating", "eats", "was eating"},
						FontB:     "English",
					}},
				})
				break
			case "2":
				// A Cloze B Given
				context.JSON(200, gin.H{
					"Type":    "A Cloze B Given",
					"Set":     1,
					"Comment": "Blah blah blah...",
					"items": []model.ClozeBAItem{{
						SoundA:    "M2",
						LanguageA: "English",
						A:         "[h]How are[-h] your parents?",
						Answers:   []string{"How are", "How were"},
						FontA:     "English",
						SoundB:    "F2",
						LanguageB: "English",
						B:         "Very well.",
						FontB:     "English",
					}},
				})
				break
			case "3":
				// A Given B Blank
				context.JSON(200, gin.H{
					"Type":    "A Given B Blank",
					"Set":     1,
					"Comment": "The verb \"to be\" often contracts...",
					"items": []model.BlankItem{{
						SoundA:    "M2",
						LanguageA: "English",
						A:         "You are not",
						FontA:     "English",
						SoundB:    "F2",
						LanguageB: "English",
						B:         []string{"You aren't", "You're not"},
						FontB:     "English",
					}},
				})
				break
			case "4":
				// Letter number match
				context.JSON(200, gin.H{
					"Type":    "A Given B Blank",
					"Set":     1,
					"Comment": "The verb \"to be\" often contracts...",
					"items": []model.LetterNumberMatchItem{{
						SoundA:    "M2",
						LanguageA: "English",
						A:         "Where is the camera?",
						FontA:     "English",
						SoundB:    "F2",
						LanguageB: "English",
						B:         "It's in your bag.",
						FontB:     "English",
					}},
				})
				break
			case "5":
				// Match up click
				context.JSON(200, gin.H{
					"Type":    "Match up click",
					"Set":     1,
					"Comment": "How do you express there ideas?",
					"items": []model.MatchUpClickItem{{
						SoundA:    "M2",
						LanguageA: "Mandarin",
						Given:     "一石二鸟",
						FontA:     "ChineseSimp",
						SoundB:    "F2",
						LanguageB: "English",
						Desired:   "To kill two birds with one stone.",
						Pieces:    []string{"to", "kill", "two", "birds", "with", "one", "stone"},
						FontB:     "English",
					}},
				})
				break
			case "6":
				// Multiple choice
				context.JSON(200, gin.H{
					"Type":    "Multiple choice",
					"Set":     1,
					"Comment": "Tough choices!",
					"items": []model.MultipleChoiceItem{{
						Sound:        "M2",
						Language:     "English",
						MainSentence: "The man is [h]in[-h] the [h]car[-h].",
						Blanks:       [][]string{{"on", "at", "under", "without"}, {"train", "helicopter", "boat"}},
						Font:         "English",
					}},
				})
				break
			case "7":
				// UNSCRAMBLE
				context.JSON(200, gin.H{
					"Type":    "Unscramble",
					"Set":     1,
					"Comment": "Blah blah blah...",
					"items": []model.UnscrambleItem{{
						SoundA:    "F2",
						LanguageA: "English",
						TOP:       "Where are you going in the afternoon?",
						FontA:     "English",
						SoundB:    "M2",
						LanguageB: "English",
						U:         []string{"I", "am", "going", "to", "school", "."},
						FontB:     "English",
					}},
				})
				break
			}
			break
		default:
			context.Status(404)
			break
		}
	})
	courseGroup.POST("/:target/:instruction/:tour/:lesson/:activity/:exercise", func(context *gin.Context) {
		context.Status(204)
	})

	scriptGroup := engine.Group("/script")
	scriptGroup.GET("/:target/:instruction", func(context *gin.Context) {
		tours, err := data.GetTourCount(false, context.Param("target"), context.Param("instruction"))
		if err != nil {
			context.Status(400)
			println(err.Error())
			return
		}
		context.String(200, strconv.Itoa(tours))
	})
	scriptGroup.GET("/:target/:instruction/:tour", func(context *gin.Context) {
		tour, err := strconv.Atoi(context.Param("tour"))
		if err != nil {
			context.Status(422)
			return
		}
		lessons, err := data.GetUnitCount(false, context.Param("target"), context.Param("instruction"), tour)
		if err != nil {
			context.Status(400)
			println(err.Error())
			return
		}
		context.String(200, strconv.Itoa(lessons))
	})
	scriptGroup.GET("/:target/:instruction/:tour/:lesson", func(context *gin.Context) {
		tour, err := strconv.Atoi(context.Param("tour"))
		if err != nil {
			context.Status(422)
			return
		}
		lesson, err := strconv.Atoi(context.Param("lesson"))
		if err != nil {
			context.Status(422)
			return
		}
		script, err := data.GetScript(false, context.Param("target"), context.Param("instruction"), tour, lesson)
		if err != nil {
			context.Status(400)
			println(err.Error())
			return
		}
		context.JSON(200, script)
	})

	imageGroup := engine.Group("/image")
	imageGroup.GET("/:id", func(context *gin.Context) {
		filePath, err := data.GetImagePath(context.Param("id"))
		if err != nil {
			context.Status(404)
			return
		}
		context.File(filePath)
	})

	fontGroup := engine.Group("/font")
	fontGroup.GET("/:language", func(context *gin.Context) {
		item, err := data.GetFont(context.Param("language"))
		if err != nil {
			context.Status(400)
			println(err.Error())
			return
		}
		context.JSON(200, *item)
	})

	progressGroup := engine.Group("/progress")
	progressGroup.GET("/:target/:instruction", func(context *gin.Context) {
		context.JSON(200, gin.H{
			"progress": 1,
			"total":    1,
			"url":      "/course/1/1/1/narration/1",
		})
	})

	err := engine.RunTLS("0.0.0.0:443", "cert/www.pem", "cert/www.key")
	if err != nil {
		print(err.Error())
	}
}
